﻿/*******************************************************************
** This code is part of Breakout.
**
** Breakout is free software: you can redistribute it and/or modify
** it under the terms of the CC BY 4.0 license as published by
** Creative Commons, either version 4 of the License, or (at your
** option) any later version.
******************************************************************/
#include "resource_manager.h"

#include <iostream>
#include <sstream>
#include <fstream>
#include "Core/base.h"

#include "Scene/Entity.h"
#include "Core/application.h"

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image/stb_image.h>

namespace CC{
// Instantiate static variables
static std::unordered_map<std::string, Shader*>    Shaders;
static std::unordered_map<std::string, Texture2D*> Textures;
static std::unordered_map<std::string, TextureCube*> TextureCubes;
// static std::unordered_map<std::string, Texture3D> Texture3Ds;
static std::unordered_map<std::string, Model*> Modeles;
// static std::unordered_map<std::string, Font> Fonts;
// static std::unordered_map<std::string, Character> Characters;

Shader* ResourceManager::LoadShader(std::string name, const char *vShaderFile, const char *fShaderFile)
{
    if (Shaders[name]) {
        return Shaders[name];
    }
    Shaders[name] = Shader::Create(name, vShaderFile, fShaderFile);
    return Shaders[name];
}

Shader* ResourceManager::GetShader(std::string name)
{
    return Shaders[name];
}

typedef struct _TextureInfo
{
    std::string file;
    std::string name;
    Entity* entity;

    void* imgData;
    int width;
    int height;
    int channels;
    Texture2D* texture2D;
    TextureType textureType;

    std::function<void(Entity* e, Texture2D* t)> callback;

    _TextureInfo(std::string f, std::string n, Entity* e, std::function<void(Entity* e, Texture2D* t)> _callback, TextureType type)
        :file(f),name(n),entity(e), imgData(NULL), texture2D(NULL)
    ,callback(_callback), textureType(type) {

    }
}TextureInfo;

typedef struct _ModelInfo
{
    std::string file;
    std::string name;
    Entity* entity;

    Model* model;
    TextureType textureType;

    std::function<void(Entity* e, Model* m)> callback;

    _ModelInfo(std::string f, std::string n, Entity* e, std::function<void(Entity* e, Model* m)> _callback, TextureType type)
        :file(f), name(n), entity(e), model(NULL)
        , callback(_callback), textureType(type) {

    }
}ModelInfo;

DWORD WINAPI ThreadFuncLoadTexture(LPVOID p)
{
    TextureInfo* info = (TextureInfo*)p;
    CC_ASSERT(info, "ThreadFuncLoadTexture error\n");

    int width, height, channels;
    // stbi_set_flip_vertically_on_load(1);
    stbi_uc *data = nullptr;
    {
        // HZ_PROFILE_SCOPE("stbi_load - OpenGLTexture2D::OpenGLTexture2D(const std::string&)");
        data = stbi_load(info->file.c_str(), &width, &height, &channels, 0);
    }

    if (data)
    {
        info->imgData = data;
        info->width = width;
        info->height = height;
        info->channels = channels;

        Application::Get().SubmitToMainThread(ThreadInfo([=](void* param) {
            TextureInfo* _info = (TextureInfo*)param;

            _info->texture2D = Texture2D::Create(_info->file, (unsigned char*)_info->imgData, _info->width, _info->height, _info->channels, _info->textureType);
            _info->texture2D->TypeName = "texture_diffuse";

            stbi_image_free((unsigned char*)_info->imgData);
            Textures[_info->name] = _info->texture2D;

            if (_info->callback) {
                _info->callback(_info->entity, _info->texture2D);
            }

            //CC_CORE_INFO("SubmitToMainThread %s\n", _info->name.c_str());

            delete _info;
        }, (void*)info));
    }

    return 0;
}

DWORD WINAPI ThreadFuncLoadModel(LPVOID p)
{
    ModelInfo* info = (ModelInfo*)p;
    CC_ASSERT(info, "ThreadFuncLoadModel error\n");


    Model* model = new Model();
    model->FilePath = info->file;
    model->Name = info->name;

    MeshHelper meshHelper;
    model->Meshes = meshHelper.MeshCreate(info->file, info->name, model->AnimationInfo, true, info->textureType);

    info->model = model;
    Modeles[info->name] = model;

    Application::Get().SubmitToMainThread(ThreadInfo([=](void* param) {
        ModelInfo* _info = (ModelInfo*)param;

        CC_ASSERT(_info->model, "ThreadFuncLoadModel model is null\n");
        for (int i = 0; i < _info->model->Meshes.size(); i++) {
            _info->model->Meshes[i].Textures.clear();
            for (int d = 0; d < _info->model->Meshes[i].TexturesData.size(); d++) {
                StdImgInfo& imgInfo = _info->model->Meshes[i].TexturesData[d];

                Texture2D* texture2D = Texture2D::Create(imgInfo.file, (unsigned char*)imgInfo.imgData, imgInfo.width, imgInfo.height, imgInfo.channels, imgInfo.textureType);
                texture2D->TypeName = imgInfo.typeName;
                _info->model->Meshes[i].Textures.push_back(texture2D);

                stbi_image_free((unsigned char*)imgInfo.imgData);
                Textures[_info->name] = texture2D;
            }
        }

        if (_info->callback) {
            _info->callback(_info->entity, _info->model);
        }

        delete _info;
    }, (void*)info));
    

    return 0;
}

Texture2D* ResourceManager::LoadTexture(const std::string file, std::string name, TextureType type)
{
    Texture2D* one = Textures[name];
    if(one){
        return one;
    }

    int width, height, channels;
    // stbi_set_flip_vertically_on_load(1);
    stbi_uc *data = nullptr;
    {
        // HZ_PROFILE_SCOPE("stbi_load - OpenGLTexture2D::OpenGLTexture2D(const std::string&)");
        data = stbi_load(file.c_str(), &width, &height, &channels, 0);
    }

    Texture2D* t = NULL;
    if (data)
    {
        t = Texture2D::Create(file, data, width, height, channels, type);
        t->TypeName = "texture_diffuse";
        Textures[name] = t;
        stbi_image_free(data);
    }

    return t;
}

Texture2D* ResourceManager::LoadTextureSync(const std::string file, std::string name, Entity* entity, std::function<void(Entity* e, Texture2D* t)> callback, TextureType type) {

    Texture2D* one = Textures[name];
    if (one) {
        if (callback) {
            callback(entity, one);
        }
        return one;
    }

    HANDLE hThread;
    DWORD  threadId;

    TextureInfo* info = new TextureInfo(file, name, entity, callback, type);
    hThread = CreateThread(NULL, 0, ThreadFuncLoadTexture, (LPVOID)info, 0, &threadId);

    return NULL;
}

Texture2D* ResourceManager::GetTexture(std::string name)
{
    return Textures[name];
}

unsigned char* ResourceManager::ResourceManager::LoadStbFunction(char const *filename, int &x, int &y, int &channels_in_file, int desired_channels)
{
    unsigned char* data = stbi_load(filename, &x, &y, &channels_in_file, desired_channels);
    return data;
}

 TextureCube* ResourceManager::LoadTextureCube(std::vector<std::string>& files, std::string name)
 {
     if (TextureCubes[name]) {
         return TextureCubes[name];
     }

     int size = files.size();
     CC_ASSERT(size, "LoadTextureCube files=0\n");

     TextureCube* texture = TextureCube::Create(files[0]);

     // load image
     
     for(int i = 0; i < size; i++){
         int width, height, nrChannels;

         unsigned char* data = stbi_load(files[i].c_str(), &width, &height, &nrChannels, 0);

         // now generate texture
         texture->Generate(i, data, width, height, nrChannels);
         //texture->TypeName = name;

         // and finally free image data
         stbi_image_free(data);
     }

     TextureCubes[name] = texture;

     return TextureCubes[name];
 }

 TextureCube* ResourceManager::GetTextureCube(std::string name)
 {
     return TextureCubes[name];
 }

// Texture3D& ResourceManager::LoadTexture3D(const char *file, string name)
// {
//     Texture3Ds[name] = loadTexture3DFromFile(file);
//     Texture3Ds[name].type = name;
//     return Texture3Ds[name];
// }

// Texture3D& ResourceManager::GetTexture3D(string name)
// {
//     return Texture3Ds[name];
// }

// Font &ResourceManager::LoadFont(const char *file, string name)
// {
//     FT_Library ft;
//     if (FT_Init_FreeType(&ft))
//         std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;

//     FT_Face face;
//     if (FT_New_Face(ft, file, 0, &face))
//         std::cout << "ERROR::FREETYPE: Failed to load font:" << file << std::endl;

//     Font font = {face, ft};
//     Fonts[name] = font;
//     return Fonts[name];
// }

// Font &ResourceManager::GetFont(string name)
// {
//     return Fonts[name];
// }

// Character& ResourceManager::LoadCharacter(Font& font, string name, unsigned int fontSize)
// {
//     FT_Set_Pixel_Sizes(font.face, 0, fontSize);

//     int len = name.size();
//     for (int i = 0; i < len; i++){
//         string one = name.substr(i, 1).c_str();
//         signed long  char_code = name[i];
//         if(char_code < 0){
//             //2 char
//             if(i+1 < len){
//                 one = name.substr(i, 2).c_str();
//                 char_code = GetCharacterIndex(one);
// //                printf("LoadCharacter %d: %s, %ld\n", i, one.c_str(), char_code);
//                 i++;
//             }
//         }
//         else{
// //            printf("LoadCharacter ascii %d: %s, %ld\n", i, one.c_str(), char_code);
//         }

//         if (FT_Load_Char(font.face, char_code, FT_LOAD_RENDER))
//             std::cout << "ERROR::FREETYTPE: Failed to load Glyph:" << one.c_str() << std::endl;

//         Texture2D texture = loadTextureFontFromFile(font);
//         Character character = {
//            new Texture2D(texture),
//             glm::ivec2(font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows),
//             glm::ivec2(font.face->glyph->bitmap_left, font.face->glyph->bitmap_top),
//             (GLuint)font.face->glyph->advance.x
//         };
//         Characters[one] = character;
//     }

//     return Characters[name.substr(0, 1)];
// }

// Character& ResourceManager::GetCharacter(string name)
// {
//     return Characters[name];
// }

Model* ResourceManager::LoadModel(const char *file, std::string name, TextureType textureType)
{
    Model* one = Modeles[name];
    if(one){
        return one;
    }

    Model* model = new Model();
    model->FilePath = file;
    model->Name = name;

    MeshHelper meshHelper;
    model->Meshes = meshHelper.MeshCreate(file, name, model->AnimationInfo, false, textureType);

    Modeles[name] = model;
    return model;
}

Model* ResourceManager::LoadModelSync(const char *file, std::string name, Entity* entity, std::function<void(Entity* e, Model* m)> callback, TextureType textureType)
{
    Model* one = Modeles[name];
    if (one) {
        if (callback) {
            callback(entity, one);
        }
        return one;
    }

    HANDLE hThread;
    DWORD  threadId;

    ModelInfo* info = new ModelInfo(file, name, entity, callback, textureType);
    hThread = CreateThread(NULL, 0, ThreadFuncLoadModel, (LPVOID)info, 0, &threadId);

    return NULL;
}

Model* ResourceManager::GetModel(std::string name)
{
    return Modeles[name];
}

void ResourceManager::Clear()
{
//     // (properly) delete all shaders	
    for (std::unordered_map<std::string, Shader*>::iterator iter = Shaders.begin(); iter != Shaders.end(); ++iter)
        delete iter->second;
//     // (properly) delete all textures
    for (std::unordered_map<std::string, Texture2D*>::iterator iter = Textures.begin(); iter != Textures.end(); ++iter)
        delete iter->second;

    for (std::unordered_map<std::string, TextureCube*>::iterator iter = TextureCubes.begin(); iter != TextureCubes.end(); ++iter)
        delete iter->second;

//     for(std::map<std::string, Texture3D>::iterator iter = Texture3Ds.begin(); iter != Texture3Ds.end(); ++iter)
//         glDeleteTextures(1, &iter->second.ID);

    for(std::unordered_map<std::string, Model*>::iterator iter = Modeles.begin(); iter != Modeles.end(); ++iter)
        delete iter->second;

//     for(std::map<std::string, Character>::iterator iter = Characters.begin(); iter != Characters.end(); ++iter){
//         if(iter->second.texture2D){
//             glDeleteTextures(1, &iter->second.texture2D->ID);
//             delete iter->second.texture2D;
//         }
//     }

//     for(std::map<std::string, Font>::iterator iter = Fonts.begin(); iter != Fonts.end(); ++iter){
//         FT_Done_Face(iter->second.face);
//         FT_Done_FreeType(iter->second.ft);

//     }
}

void ResourceManager::ClearTexture(const char* name) {
    std::unordered_map<std::string, Texture2D*>::iterator iter = Textures.find(name);
    if (iter != Textures.end()) {
        unsigned int id = iter->second->GetID();
        Textures.erase(iter);
        glDeleteTextures(1, &id);
    }
}

// //void ResourceManager::ClearTextureGL(std::string name)
// //{
// //    std::map<std::string, Texture2D>::iterator iter = Textures.find(name);
// //    if(iter != Textures.end()){
// //        unsigned int id = iter->second.ID;
// //        Textures.erase(iter);
// //        glDeleteTextures(1, &id);
// //    }
// //}

 //Shader ResourceManager::loadShaderFromFile(const char *vShaderFile, const char *fShaderFile, const char *gShaderFile)
 //{    
 //    Shader shader;
 //    shader.compile(vShaderFile, fShaderFile, gShaderFile);
 //    return shader;
 //}

// Texture2D ResourceManager::loadTextureFromFile(const char *file, bool alpha)
// {
//     // create texture object
//     Texture2D texture;

//     // load image
//     int width, height, nrChannels;
//     unsigned char* data = stbi_load(file, &width, &height, &nrChannels, 0);
//     printf("loadTextureFromFile file=%s, w=%d, h=%d, nrChannels=%d\n", file, width, height, nrChannels);
//     if(4 == nrChannels){
//         texture.Internal_Format = GL_RGBA;
//         texture.Image_Format = GL_RGBA;
//     }
//     // now generate texture
//     texture.generate(width, height, data);

//     // and finally free image data
//     stbi_image_free(data);
//     return texture;
// }

// Texture3D ResourceManager::loadTexture3DFromFile(const char *file, bool alpha)
// {
//     Texture3D texture;

//     // load image
//     int width, height, nrChannels;
//     unsigned char* data = stbi_load(file, &width, &height, &nrChannels, 0);
//     printf("loadTexture3DFromFile file=%s, w=%d, h=%d, nrChannels=%d\n", file, width, height, nrChannels);
//     if(4 == nrChannels){
//         texture.Internal_Format = GL_RGBA;
//         texture.Image_Format = GL_RGBA;
//     }
//     // now generate texture
//     //w * h = w * h * depth;
//     int w = width/4;
//     int h = height/4;
//     texture.generate(w, h, 16, data);

//     // and finally free image data
//     stbi_image_free(data);
//     return texture;
// }

// Texture2D ResourceManager::loadTextureFontFromFile(Font &font)
// {
//     Texture2D texture;

//     texture.Internal_Format = GL_RED;
//     texture.Image_Format = GL_RED;
//     texture.Wrap_S = GL_CLAMP_TO_EDGE;
//     texture.Wrap_T = GL_CLAMP_TO_EDGE;
//     // now generate texture
//     texture.generate(font.face->glyph->bitmap.width, font.face->glyph->bitmap.rows, font.face->glyph->bitmap.buffer);

//     return texture;
// }

// std::string directory;

// Model* ResourceManager::loadModelFromFile(const char *file)
// {
//     Model* model = new Model();

//     // Assimp::Importer import;
//     // const aiScene* scene = import.ReadFile(file, aiProcess_Triangulate | aiProcess_FlipUVs);

//     const aiScene* scene = aiImportFile(file,
//             aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);

//     // If the import failed, report it
//     if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
//     {
//         std::cout << "ERROR::ASSIMP::" << aiGetErrorString() << std::endl;
//         return model;
//     }

//     std::string path = std::string(file);
//     directory = path.substr(0, path.find_last_of('/'));

//    // printf("directory=%s\n", directory.c_str());
    
//     // Now we can access the file's contents.
//     processNode(scene->mRootNode, scene, *model);

//     // printf("model.meshes=%d\n", model.meshes.size());

//     return model;
// }

// //Animator* ResourceManager::loadAnimatorFromFile(const char *file, Model& model)
// //{
// //    std::string animationPath = std::string(file);
// //    Animation* a = new Animation(animationPath, model);
// //    if(!a){
// //        printf("loadAnimatorFromFile Animation error.\n");
// //    }
// //    Animator* at = new Animator(a);
// //    if(!at){
// //        printf("loadAnimatorFromFile Animator error.\n");
// //    }
// //    return at;
// //}

// void ResourceManager::processNode(aiNode *node, const aiScene *scene, Model& model)
// {
//      // printf("node->mNumMeshes=%d;node->mNumChildren=%d\n", node->mNumMeshes, node->mNumChildren);
//     unsigned int i = 0;
//     for (i = 0; i < node->mNumMeshes; ++i)
//     {
//         C_STRUCT aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
//         model.meshes.push_back(processMesh(mesh, scene, model));
//     }
//     // 接下来对它的子节点重复这一过程
//     for (i = 0; i < node->mNumChildren; ++i)
//     {
//         processNode(node->mChildren[i], scene, model);
//     }
// }

// Mesh ResourceManager::processMesh(aiMesh *mesh, const aiScene *scene, Model& model){
//     std::vector<Vertex> vertices;
//     std::vector<unsigned int> indices;
//     std::vector<Texture2D> textures;

// //     printf("mesh->mNumVertices=%d;mNumFaces=%d\n", mesh->mNumVertices, mesh->mNumFaces);
//     for (unsigned int i = 0; i < mesh->mNumVertices; i++)
//     {
//         Vertex vertex;
//         setVertexBoneDataToDefault(vertex);
//         vertex.Position = AssimpGLMHelpers::GetGLMVec(mesh->mVertices[i]);
        
//         if (mesh->HasNormals())
//         {
//             vertex.Normal = AssimpGLMHelpers::GetGLMVec(mesh->mNormals[i]);
//         }
//         // texture coordinates
//         if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
//         {
//             glm::vec2 vec;
//             // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
//             // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
//             vec.x = mesh->mTextureCoords[0][i].x;
//             vec.y = mesh->mTextureCoords[0][i].y;
//             vertex.TexCoords = vec;
//             // tangent
//             // if (mesh->mTangents) {
//             //     vertex.Tangent = AssimpGLMHelpers::GetGLMVec(mesh->mTangents[i]);;
//             // }

//             // // bitangent
//             // if (mesh->mBitangents) {
//             //     vertex.Bitangent = AssimpGLMHelpers::GetGLMVec(mesh->mBitangents[i]);;
//             // }

//         }
//         else
//             vertex.TexCoords = glm::vec2(0.0f, 0.0f);

//         vertices.push_back(vertex);
//     }

//     // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
//     for (unsigned int i = 0; i < mesh->mNumFaces; i++)
//     {
//         aiFace face = mesh->mFaces[i];
//         // retrieve all indices of the face and store them in the indices vector
//         for (unsigned int j = 0; j < face.mNumIndices; j++)
//             indices.push_back(face.mIndices[j]);
//     }
//     // for(int i=0;i<indices.size();i++){
//     //     printf("%d:%d\n", i, indices[i]);
//     // }

//     // 处理材质
//     Material colorMaterial;
//     bool hasColorMaterial = false;
//     if (mesh->mMaterialIndex >= 0)
//     {
//         aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];

//         std::vector<Texture2D> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
//         textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
//         // 2. specular maps
//         std::vector<Texture2D> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
//         textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
//         // 3. normal maps
//         std::vector<Texture2D> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
//         textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
//         // 4. height maps
//         std::vector<Texture2D> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
//         textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());

//         if(material->GetTextureCount(aiTextureType_DIFFUSE) == 0
//                 && material->GetTextureCount(aiTextureType_SPECULAR) == 0){
//             colorMaterial = loadMaterialWithoutTextures(material);
//             hasColorMaterial = true;
//         }
//     }

//     extractBoneWeightForVertices(vertices, mesh,scene, model);

//     if(hasColorMaterial){
//         return Mesh(vertices, indices, colorMaterial);
//     }
//     else{
//         return Mesh(vertices, indices, textures);
//     }
// }

// std::vector<Texture2D> ResourceManager::loadMaterialTextures(aiMaterial *mat, aiTextureType type, std::string typeName)
// {
//     std::vector<Texture2D> textures;
//     for (unsigned int i = 0; i < mat->GetTextureCount(type); i++)
//     {
//         aiString str;
//         mat->GetTexture(type, i, &str);
//         bool skip = false;

//         if (!skip)
//         {   
//             // 如果纹理还没有被加载，则加载它
//             std::string strlinux = std::string(str.C_Str());
//             // if(int i=strlinux.find("\\") != std::string::npos){
//                //  printf("~%s:%d typeName=%s, %s\n", strlinux.c_str(), i, typeName.c_str(), str.C_Str());
//             //     strlinux = strlinux.replace(i, 1, "/");
//             // }
//             //std::replace(strlinux.begin(), strlinux.end(), "\\", "/");

//             Texture2D t = LoadTexture((directory + "/" + strlinux).c_str(), str.C_Str());
//             t.type = typeName;
//             textures.push_back(t);
//         }
//     }
//     return textures;
// }

// Material ResourceManager::loadMaterialWithoutTextures(aiMaterial *mat)
// {
//     //printf("loadMaterialWithoutTextures\n");
//     Material result;
//     aiColor3D color;
//     //读取mtl文件顶点数据
//     mat->Get(AI_MATKEY_COLOR_AMBIENT, color);
//     result.ambient = glm::vec3(color.r, color.g, color.b);
//     mat->Get(AI_MATKEY_COLOR_DIFFUSE, color);
//     result.diffuse = glm::vec3(color.r, color.g, color.b);
//     mat->Get(AI_MATKEY_COLOR_SPECULAR, color);
//     result.specular = glm::vec3(color.r, color.g, color.b);
//     return result;
// }


// void ResourceManager::extractBoneWeightForVertices(std::vector<Vertex>& vertices, aiMesh* mesh,
//     const aiScene* scene, Model& model)
// {
//     auto& boneInfoMap = model.getBoneInfoMap();
//     int& boneCount = model.getBoneCount();

// //     printf("mesh->mNumBones=%d\n", mesh->mNumBones);
//     for (int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
//     {
//         int boneID = -1;
//         std::string boneName = mesh->mBones[boneIndex]->mName.C_Str();

//         if (boneInfoMap.find(boneName) == boneInfoMap.end())
//         {
//             BoneInfo newBoneInfo;
//             newBoneInfo.id = boneCount;
//             newBoneInfo.offset = AssimpGLMHelpers::ConvertMatrixToGLMFormat(mesh->mBones[boneIndex]->mOffsetMatrix);
//             boneInfoMap[boneName] = newBoneInfo;
//             boneID = boneCount;
//             boneCount++;
// //             printf("extractBoneWeightForVertices boneID=%d: %s, newBoneInfo.id =%d\n", boneID, boneName.c_str(), newBoneInfo.id );
//         }
//         else
//         {
//             boneID = boneInfoMap[boneName].id;
//         }
//         assert(boneID != -1);
//         auto weights = mesh->mBones[boneIndex]->mWeights;
//         int numWeights = mesh->mBones[boneIndex]->mNumWeights;

//         // printf("numWeights=%d\n", numWeights);

//         for (int weightIndex = 0; weightIndex < numWeights; ++weightIndex)
//         {
//             int vertexId = weights[weightIndex].mVertexId;
//             float weight = weights[weightIndex].mWeight;
//             // printf("n````````````vertexId=%d %d %d %f\n", vertexId, vertices.size(), boneID, weight);
//             assert(vertexId <= vertices.size());
//             setVertexBoneData(vertices[vertexId], boneID, weight);
//             // printf("%f,%f,%f,%f\n", vertices[vertexId].m_Weights[0], vertices[vertexId].m_Weights[1], 
//             //     vertices[vertexId].m_Weights[2], vertices[vertexId].m_Weights[3]);
//         }
//     }

//     // printf("model.getBoneCount()=%d\n", model.getBoneCount());
// }

// void ResourceManager::setVertexBoneData(Vertex& vertex, int boneID, float weight)
// {
//     for (int i = 0; i < MAX_BONE_INFLUENCE; ++i)
//     {
//         if (vertex.m_Weights[i] == 0.0)
//         {
//             vertex.m_Weights[i] = weight;
//             vertex.m_BoneIDs[i] = boneID;
//             // printf("setVertexBoneData %d,%d %d;weight=%f\n", vertex.m_BoneIDs[i], boneID, (int)vertex.m_BoneIDs[i], weight);
//             break;
//         }
//     }
// }

// void ResourceManager::setVertexBoneDataToDefault(Vertex& vertex)
// {
//     for (int i = 0; i < MAX_BONE_INFLUENCE; i++)
//     {
//         vertex.m_BoneIDs[i] = -1;
//         vertex.m_Weights[i] = 0.0f;
//     }
// }
}
